home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 24
/
Aminet 24 (1998)(GTI - Schatztruhe)[!][Apr 1998].iso
/
Aminet
/
comm
/
mail
/
Mutt089src.lha
/
Mutt-0.89i-AMIGA
/
src
/
rx
/
rxnfa.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-01-28
|
19KB
|
854 lines
/* Copyright (C) 1995, 1996 Tom Lord
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* Tom Lord (lord@cygnus.com, lord@gnu.ai.mit.edu)
*/
#include "rxall.h"
#include "rxnfa.h"
#define remalloc(M, S) (M ? realloc (M, S) : malloc (S))
/* {Low Level Data Structure Code}
*/
/* Constructs a new nfa node. */
#ifdef __STDC__
struct rx_nfa_state *
rx_nfa_state (struct rx *rx)
#else
struct rx_nfa_state *
rx_nfa_state (rx)
struct rx *rx;
#endif
{
struct rx_nfa_state * n = (struct rx_nfa_state *)malloc (sizeof (*n));
if (!n)
return 0;
rx_bzero ((char *)n, sizeof (*n));
n->next = rx->nfa_states;
rx->nfa_states = n;
return n;
}
#ifdef __STDC__
static void
rx_free_nfa_state (struct rx_nfa_state * n)
#else
static void
rx_free_nfa_state (n)
struct rx_nfa_state * n;
#endif
{
free ((char *)n);
}
/* This adds an edge between two nodes, but doesn't initialize the
* edge label.
*/
#ifdef __STDC__
struct rx_nfa_edge *
rx_nfa_edge (struct rx *rx,
enum rx_nfa_etype type,
struct rx_nfa_state *start,
struct rx_nfa_state *dest)
#else
struct rx_nfa_edge *
rx_nfa_edge (rx, type, start, dest)
struct rx *rx;
enum rx_nfa_etype type;
struct rx_nfa_state *start;
struct rx_nfa_state *dest;
#endif
{
struct rx_nfa_edge *e;
e = (struct rx_nfa_edge *)malloc (sizeof (*e));
if (!e)
return 0;
e->next = start->edges;
start->edges = e;
e->type = type;
e->dest = dest;
return e;
}
#ifdef __STDC__
static void
rx_free_nfa_edge (struct rx_nfa_edge * e)
#else
static void
rx_free_nfa_edge (e)
struct rx_nfa_edge * e;
#endif
{
free ((char *)e);
}
/* This constructs a POSSIBLE_FUTURE, which is a kind epsilon-closure
* of an NFA. These are added to an nfa automaticly by eclose_nfa.
*/
#ifdef __STDC__
static struct rx_possible_future *
rx_possible_future (struct rx * rx,
struct rx_se_list * effects)
#else
static struct rx_possible_future *
rx_possible_future (rx, effects)
struct rx * rx;
struct rx_se_list * effects;
#endif
{
struct rx_possible_future *ec;
ec = (struct rx_possible_future *) malloc (sizeof (*ec));
if (!ec)
return 0;
ec->destset = 0;
ec->next = 0;
ec->effects = effects;
return ec;
}
#ifdef __STDC__
static void
rx_free_possible_future (struct rx_possible_future * pf)
#else
static void
rx_free_possible_future (pf)
struct rx_possible_future * pf;
#endif
{
free ((char *)pf);
}
#ifdef __STDC__
static void
rx_free_nfa_graph (struct rx *rx)
#else
static void
rx_free_nfa_graph (rx)
struct rx *rx;
#endif
{
while (rx->nfa_states)
{
while (rx->nfa_states->edges)
{
switch (rx->nfa_states->edges->type)
{
case ne_cset:
rx_free_cset (rx->nfa_states->edges->params.cset);
break;
default:
break;
}
{
struct rx_nfa_edge * e;
e = rx->nfa_states->edges;
rx->nfa_states->edges = rx->nfa_states->edges->next;
rx_free_nfa_edge (e);
}
} /* while (rx->nfa_states->edges) */
{
/* Iterate over the partial epsilon closures of rx->nfa_states */
struct rx_possible_future * pf = rx->nfa_states->futures;
while (pf)
{
struct rx_possible_future * pft = pf;
pf = pf->next;
rx_free_possible_future (pft);
}
}
{
struct rx_nfa_state *n;
n = rx->nfa_states;
rx->nfa_states = rx->nfa_states->next;
rx_free_nfa_state (n);
}
}
}
/* {Translating a Syntax Tree into an NFA}
*
*/
/* This is the Thompson regexp->nfa algorithm.
* It is modified to allow for `side-effect epsilons.' Those are
* edges that are taken whenever a similarly placed epsilon edge
* would be, but which also imply that some side effect occurs
* when the edge is taken.
*
* Side effects are used to model parts of the pattern langauge
* that are not regular.
*/
#ifdef __STDC__
int
rx_build_nfa (struct rx *rx,
struct rexp_node *rexp,
struct rx_nfa_state **start,
struct rx_nfa_state **end)
#else
int
rx_build_nfa (rx, rexp, start, end)
struct rx *rx;
struct rexp_node *rexp;
struct rx_nfa_state **start;
struct rx_nfa_state **end;
#endif
{
struct rx_nfa_edge *edge;
/* Start & end nodes may have been allocated by the caller. */
*start = *start ? *start : rx_nfa_state (rx);
if (!*start)
return 0;
if (!rexp)
{
*end = *start;
return 1;
}
*end = *end ? *end : rx_nfa_state (rx);
if (!*end)
{
rx_free_nfa_state (*start);
return 0;
}
switch (rexp->type)
{
case r_cset:
edge = rx_nfa_edge (rx, ne_cset, *start, *end);
(*start)->has_cset_edges = 1;
if (!edge)
return 0;
edge->params.cset = rx_copy_cset (rx->local_cset_size,
rexp->params.cset);
if (!edge->params.cset)
{
rx_free_nfa_edge (edge);
return 0;
}
return 1;
case r_string:
{
if (rexp->params.cstr.len == 1)
{
edge = rx_nfa_edge (rx, ne_cset, *start, *end);
(*start)->has_cset_edges = 1;
if (!edge)
return 0;
edge->params.cset = rx_cset (rx->local_cset_size);
if (!edge->params.cset)
{
rx_free_nfa_edge (edge);
return 0;
}
RX_bitset_enjoin (edge->params.cset, rexp->params.cstr.contents[0]);
return 1;
}
else
{
struct rexp_node copied;
struct rx_nfa_state * shared;
copied = *rexp;
shared = 0;
copied.params.cstr.len--;
copied.params.cstr.contents++;
if (!rx_build_nfa (rx, &copied, &shared, end))
return 0;
copied.params.cstr.len = 1;
copied.params.cstr.contents--;
return rx_build_nfa (rx, &copied, start, &shared);
}
}
case r_opt:
return (rx_build_nfa (rx, rexp->params.pair.left, start, end)
&& rx_nfa_edge (rx, ne_epsilon, *start, *end));
case r_plus:
{
struct rx_nfa_state * star_start = 0;
struct rx_nfa_state * star_end = 0;
struct rx_nfa_state * shared;
shared = 0;
if (!rx_build_nfa (rx, rexp->params.pair.left, start, &shared))
return 0;
return (rx_build_nfa (rx, rexp->params.pair.left,
&star_start, &star_end)
&& star_start
&& star_end
&& rx_nfa_edge (rx, ne_epsilon, star_start, star_end)
&& rx_nfa_edge (rx, ne_epsilon, shared, star_start)
&& rx_nfa_edge (rx, ne_epsilon, star_end, *end)
&& rx_nfa_edge (rx, ne_epsilon, star_end, star_start));
}
case r_interval:
case r_star:
{
struct rx_nfa_state * star_start = 0;
struct rx_nfa_state * star_end = 0;
return (rx_build_nfa (rx, rexp->params.pair.left,
&star_start, &star_end)
&& star_start
&& star_end
&& rx_nfa_edge (rx, ne_epsilon, star_start, star_end)
&& rx_nfa_edge (rx, ne_epsilon, *start, star_start)
&& rx_nfa_edge (rx, ne_epsilon, star_end, *end)
&& rx_nfa_edge (rx, ne_epsilon, star_end, star_start));
}
case r_cut:
{
struct rx_nfa_state * cut_end = 0;
cut_end = rx_nfa_state (rx);
if (!(cut_end && rx_nfa_edge (rx, ne_epsilon, *start, cut_end)))
{
rx_free_nfa_state (*start);
rx_free_nfa_state (*end);
if (cut_end)
rx_free_nfa_state (cut_end);
return 0;
}
cut_end->is_final = rexp->params.intval;
return 1;
}
case r_parens:
return rx_build_nfa (rx, rexp->params.pair.left, start, end);
case r_concat:
{
struct rx_nfa_state *shared = 0;
return
(rx_build_nfa (rx, rexp->params.pair.left, start, &shared)
&& rx_build_nfa (rx, rexp->params.pair.right, &shared, end));